package cn.wp.ewallet.wallet.extension.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.novacrypto.bip39.MnemonicGenerator;
import io.github.novacrypto.bip39.SeedCalculator;
import io.github.novacrypto.bip39.Words;
import io.github.novacrypto.bip39.wordlists.English;
import io.github.novacrypto.hashing.Sha256;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.web3j.crypto.*;
import org.web3j.protocol.ObjectMapperFactory;
import org.web3j.utils.Numeric;

import java.math.BigDecimal;
import java.security.SecureRandom;

/**
 * 钱包处理工具
 * zhangyongli
 * Created by zhangyongli on 2020/1/9
 */
@Slf4j
public class EwalletWalletUtil {

    /**
     * 币种单位转换
     * 获取低位数据，即乘以10的N次方
     * @param value -- 待转换数据
     * @param decimals -- 精度
     * @return
     */
    public static BigDecimal toLowerWei(BigDecimal value, BigDecimal decimals) {
        if (null == value) {
            return null;
        }

        BigDecimal tmp = value.multiply(BigDecimal.valueOf(Math.pow(Double.valueOf(10), decimals.doubleValue())));
        //数据没有小数时，不返回小数点后面的0
        return BigDecimal.valueOf(Double.valueOf(tmp.toPlainString())).stripTrailingZeros();
    }

    /**
     * 币种单位转换
     * 获取高位数据，即除以10的N次方
     * @param value -- 待转换数据
     * @param decimals -- 精度
     * @return
     */
    public static BigDecimal toUpperWei(BigDecimal value, BigDecimal decimals) {
        if (null == value) {
            return null;
        }
        BigDecimal tmp = value.divide(BigDecimal.valueOf(Math.pow(Double.valueOf(10), decimals.doubleValue())));
        return BigDecimal.valueOf(Double.valueOf(tmp.toPlainString())).stripTrailingZeros();
    }

    /**
     * 助记词生成
     * @return
     */
    public static String generateMnemonics() {
        StringBuilder sb = new StringBuilder();
        byte[] entropy = new byte[Words.TWELVE.byteLength()];
        new SecureRandom().nextBytes(entropy);
        new MnemonicGenerator(English.INSTANCE)
                .createMnemonic(entropy, sb::append);
        return sb.toString();
    }

    /**
     * 创建钱包,返回证书
     * @return
     */
    public static Credentials createWallet() {
        //根据助记词生成种子，不设密码
        byte[] seed = new SeedCalculator().calculateSeed(generateMnemonics(), "");

        //根据seed生成公钥、私钥等
        ECKeyPair ecKeyPair = ECKeyPair.create(Sha256.sha256(seed));

        //根据公钥 私钥 密码 得到 生成钱包文件keystore，不设密码
        return Credentials.create(ecKeyPair);
    }

    /**
     * 导出keystore
     * @return
     */
    public static String exportKeyStore(ECKeyPair ecKeyPair) {

        try {
            //根据公钥 私钥 密码 得到 生成钱包文件keystore，不设密码
            WalletFile walletFile = Wallet.createLight("", ecKeyPair);
            //获取keystore文件
            ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
            String keystore = objectMapper.writeValueAsString(walletFile);
            return keystore;
        } catch (CipherException e) {
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成证书
     * @param privateKey
     * @return
     */
    public static Credentials loadCredentials(String privateKey) {
        return Credentials.create(privateKey);
    }

    /**
     * 校验地址是否是ETH地址
     * @param input
     * @return
     */
    public static boolean isETHValidAddress(String input) {
        if (StringUtils.isEmpty(input) || !input.startsWith("0x")) {
            return false;
        }
        return isValidAddress(input);
    }

    /**
     * 校验地址长度
     * @param input
     * @return
     */
    public static boolean isValidAddress(String input) {
        String cleanInput = Numeric.cleanHexPrefix(input);

        try {
            Numeric.toBigIntNoPrefix(cleanInput);
        } catch (NumberFormatException e) {
            return false;
        }

        return cleanInput.length() == 40;
    }



}
